home *** CD-ROM | disk | FTP | other *** search
- /* Copyright 1988, Gail Zacharias. All rights reserved.
- * Permission is hereby granted to copy, reproduce, redistribute or
- * otherwise use this software provided there is no monetary profit
- * gained specifically from its use or reproduction, it is not sold,
- * rented, traded or otherwise marketed, and this copyright notice
- * and the software version number is included prominently in any copy
- * made.
- * This is muntar version 1.0.
- *
- * Send comments, suggestions, bug reports (not bloody likely), feature
- * requests, etc. to gz@entity.com.
- *
- * muntar version 1.0.1.
- * Modified by Sak Wathanasin (sw@network-analysis-ltd.co.uk) to compile
- * with MPW 3.1/2.
- *
- */
-
- char *Program, *Version = "1.0.1";
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <files.h>
- #include <errors.h>
-
- /* Sak W mods */
- #define MPS 'MPS '
- #define TEXT 'TEXT'
-
- /* The do {} while(0) is for syntactic reasons. MPW C will optimize it out. */
- #define mcopy(dest, src, len) \
- do { char *_dp = (char *)(dest), *_sp = (char *)(src); \
- int _i = (len); \
- while (--_i>=0) *_dp++ = *_sp++; \
- } while(0)
-
- struct {
- char name[100];
- char mode[8];
- char uid[8];
- char gid[8];
- char size[12];
- char mtime[12];
- char chksum[8];
- char linkflag;
- char linkname[100];
- char magic[8];
- char uname[32];
- char gname[32];
- char devmajor[8];
- char devminor[8];
- char fill[167];
- } tarh;
- #define tarsz(n) (((n)+511L) & -512L)
-
- struct {
- unsigned char nlen;
- char name[63];
- FInfo finfo;
- char protected;
- char zero;
- long dflen;
- long rflen;
- long cdate;
- long mdate;
- char unused[29];
- } macbinh;
-
- #define macbinsz(n) (((n)+127L) & -128L)
-
- FILE *tarf = (FILE *) NULL;
-
- #define readblock(buf, size) ((size) == fread((char *) buf, 1, (size), tarf))
-
- StringPtr c2pstr();
-
- OSType filecreator = MPS;
-
- int listonly = 0,
- binary = 0,
- dataonly = 0,
- verbose = 0,
- ignore_cdate = 0,
- ignore_mdate = 0;
-
- char **files = (char **) NULL;
- int *ffound = (int *) NULL;
-
- main (argc, argv)
- char **argv;
- {
- Program = argv[0];
- while (--argc > 0 && **++argv == '-') {
- char *argp = &argv[0][1];
- do switch (*argp++) {
- case 'l': verbose = listonly = 1; break;
- case 'v': verbose = 1; break;
- case 'b': binary = 1; break;
- case 'u': dataonly = 1; break;
- case 'm': ignore_mdate = 1; break;
- case 'd': ignore_cdate = 1; break;
- case 'c': if (*argp == '\0') {
- if (--argc == 0) goto badarg;
- argp = *++argv;
- }
- if (*argp == '\0' || strlen(argp) > 4) goto badarg;
- filecreator = 0x20202020L;
- { char *cp = (char *)&filecreator;
- while (*argp) *cp++ = *argp++;
- }
- break;
- case 'f': if (tarf) goto badarg;
- if (*argp == '\0') {
- if (--argc == 0) goto badarg;
- argp = *++argv;
- }
- if (!strcmp(argp, "-")) tarf = stdin;
- else if (!(tarf = fopen(argp, "r")))
- fatal("Cannot open %s for reading.", argp);
- argp = "";
- break;
- default: goto badarg;
- } while (*argp);
- }
- if (!tarf) tarf = stdin;
- if (argc) {
- files = argv;
- files[argc] = (char *) NULL;
- ffound = (int *)malloc((size_t)(argc * sizeof(int)));
- if (!ffound) fatal("Out of memory.");
- while (argc) ffound[--argc] = 0;
- }
- untar();
- if (tarf != stdin) fclose(tarf);
- if (ffound) free(ffound);
- return 0;
-
- badarg:
- fprintf(stderr, "muntar Version %s by gz@entity.com. Usage: \n", Version);
- fprintf(stderr, "%s [-lvubdm] [-c XXXX] [-f tarfile] filenames...\n", Program);
- fprintf(stderr, "Extracts the named files from a tar archive.\n\
- -l = just list file names, do not actually extract any files.\n\
- -v = verbose: list names of files as extract them.\n\
- -u = do not try to detect and handle macbinary files.\n\
- -b = do not convert LF to CR in non-macbinary files.\n\
- -d = do not restore creation dates in macbinary files.\n");
- fprintf(stderr, " -m = do not restore modification dates in macbinary files.\n\
- -c XXXX = set file creator to XXXX (default is MPS) in non-macbinary files.\n\
- -f tarfile = read input from tarfile (instead of standard input).\n\
- -H = show this help message.\n\
- If no filenames are specified, all files in the archive will be\n\
- extracted (or listed).\n\n\
- This is freeware. If you paid money for this program, you got ripped off.\n");
- return 2;
- }
-
- untar ()
- {
- long size, chksum, hchksum;
- int i;
- while (readblock(&tarh, sizeof(tarh))) {
- for (i=0; i < sizeof(tarh) && tarh.name[i]=='\0'; ++i) ;
- if (i == sizeof(tarh)) break;
- hchksum = untar_number(tarh.chksum);
- for (i=0; i < 8; ++i) tarh.chksum[i] = ' ';
- for (i=chksum=0; i < sizeof(tarh); ++i) chksum += (unsigned char)tarh.name[i];
- if (chksum != hchksum)
- fatal("Bad header checksum (got 0%lo, expected 0%lo) for %s",
- chksum, hchksum, tarh.name);
- switch (tarh.linkflag) {
- case '\0': case '0': untar_file(); break;
- case '1': case '2': untar_link(); break;
- case '5': untar_directory(); break;
- default: fatal("Unknown header type (0%o)", tarh.linkflag);
- }
- }
- if (!feof(tarf) && ferror(tarf)) readerr();
-
- for(i=0; files[i]; ++i) if (!ffound[i])
- fprintf(stderr,"%s: Warning - File %s not found.\n", Program, files[i]);
- }
-
- untar_file ()
- {
- long fsize = untar_number(tarh.size);
- if (tarh.name[strlen(tarh.name)-1] == '/') return untar_directory();
- unix2mac(tarh.name);
- if (!dataonly && chkmacbin(fsize)) untar_macbin(fsize);
- else untar_data(fsize);
- }
-
- chkmacbin (fsize)
- long fsize;
- {
- char buf[128];
- if (fsize < 128) return 0;
- if (!readblock(buf, 128)) readerr();
- mcopy(&macbinh, &buf[1], sizeof(macbinh));
- if (buf[0] == 0 && macbinh.zero == 0 &&
- macbinh.nlen < 64 && macbinh.nlen > 0 &&
- macbinh.dflen >= 0 && macbinh.rflen >= 0 &&
- (unsigned) (macbinsz(macbinh.dflen) + macbinsz(macbinh.rflen) + 128L)
- <= (unsigned) fsize) return 1;
- fseek(tarf, -128L, 1);
- return 0;
- }
-
- untar_data (fsize)
- long fsize;
- {
- IOParam pb;
- char fname[110];
- int ignore = ignore_file(tarh.name);
-
- if (verbose && !ignore) {
- printf("X %s (%ld bytes)\n", tarh.name, fsize);
- fflush(stdout);
- }
- if (listonly || ignore) {
- fseek(tarf, tarsz(fsize), 1);
- return;
- }
- create_file(tarh.name);
- openpb(&pb, strcpy(fname, tarh.name), fsWrPerm);
- pb.ioReqCount = sizeof(tarh);
- writefork(&pb, fsize, binary);
- }
-
- untar_macbin (fsize)
- long fsize;
- {
- IOParam pb;
- char fname[170], *cp;
- long endpos = ftell(tarf) - 128 + tarsz(fsize);
- int ignore;
- for(cp = tarh.name+strlen(tarh.name); cp != tarh.name && cp[-1] != ':'; --cp);
- mcopy(cp, macbinh.name, macbinh.nlen);
- cp[macbinh.nlen] = '\0';
- ignore = ignore_file(tarh.name);
- if (verbose && !ignore) {
- printf("Macbin %s (%ld+%ld bytes)\n", tarh.name, macbinh.dflen, macbinh.rflen);
- fflush(stdout);
- }
- if (!listonly && !ignore) {
- create_file(tarh.name);
- strcpy(fname, tarh.name); /* For error messages */
- openpb(&pb, fname, fsWrPerm);
- pb.ioReqCount = 128;
- writefork(&pb, macbinh.dflen, 1);
- pb.ioNamePtr = fname;
- pb.ioVRefNum = 0;
- pb.ioVersNum = 0;
- pb.ioPermssn = fsWrPerm;
- pb.ioMisc = 0;
- if (PBOpenRF((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- pb.ioReqCount = 128;
- writefork(&pb, macbinh.rflen, 1);
- setmacbin(fname);
- }
- fseek(tarf, endpos, 0);
- }
-
- writefork(pb, size, binp)
- IOParam *pb;
- long size;
- {
- int i;
- pb->ioPosMode = fsAtMark;
- pb->ioPosOffset = 0;
- pb->ioBuffer = (Ptr)&tarh;
- while (size) {
- if (!readblock(&tarh, pb->ioReqCount)) {
- PBClose((ParmBlkPtr)pb, 0);
- readerr();
- }
- if (!binp)
- for (i=0; i < pb->ioReqCount; ++i)
- if (tarh.name[i] == 'J'-'@') tarh.name[i] = 'M'-'@';
- if (size < pb->ioReqCount) pb->ioReqCount = size;
- size -= pb->ioReqCount;
- if (PBWrite((ParmBlkPtr)pb, 0) || pb->ioActCount != pb->ioReqCount) {
- int err = pb->ioResult;
- PBClose((ParmBlkPtr)pb, 0);
- pb->ioResult = err;
- pbsyserr(pb);
- }
- }
- PBClose((ParmBlkPtr)pb, 0);
- }
-
-
- setmacbin (fname)
- char *fname;
- {
- FileParam pb;
- pb.ioNamePtr = fname;
- pb.ioVRefNum = 0;
- pb.ioFVersNum = 0;
- pb.ioFDirIndex = 0;
- if (PBGetFInfo((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- mcopy(&pb.ioFlFndrInfo, &macbinh.finfo, sizeof(FInfo));
- if (!ignore_cdate) pb.ioFlCrDat = macbinh.cdate;
- if (!ignore_mdate) pb.ioFlMdDat = macbinh.mdate;
- if (PBSetFInfo((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- }
-
- untar_directory ()
- {
- int len = strlen(tarh.name);
-
- if (len && tarh.name[len-1] != '/') {
- tarh.name[len] = '/';
- tarh.name[len+1] = '\0';
- }
- unix2mac(tarh.name);
- if (!tarh.name[1] || ignore_file(tarh.name)) return;
- if (listonly) {
- printf("Directory \"%s\"\n", tarh.name);
- fflush(stdout);
- return;
- }
- create_directory(tarh.name);
- }
-
- /* fname may contain a filename after the last :, it will be ignored */
- create_directory (fname)
- char *fname;
- {
- HFileParam pb;
- char name[128], *cp, *bp;
-
- cp = fname + strlen(fname);
- for (bp = fname; *bp == ':'; ++bp);
-
- pb.ioNamePtr = (StringPtr) name;
- do {
- while (cp[-1] != ':') --cp;
- if (cp == bp) fatal("%s - Bad directory name", fname);
- strncpy(name+1, fname, name[0] = --cp - fname);
- pb.ioVRefNum = 0;
- pb.ioDirID = 0;
- } while (PBDirCreate((HParmBlkPtr)&pb, 0) == dirNFErr);
- if (pb.ioResult) pbsyserr(&pb);
- while (1) {
- while (*++cp != ':') if (!*cp) return;
- strncpy(name+1, fname, name[0] = cp - fname);
- pb.ioVRefNum = 0;
- pb.ioDirID = 0;
- if (PBDirCreate((HParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- }
- }
-
- create_file (fname)
- char *fname;
- {
- FileParam pb;
- char name[128];
- static int fno = 1;
-
- pb.ioNamePtr = c2pstr(strcpy(name, fname));
- pb.ioVRefNum = 0;
- pb.ioFVersNum = 0;
- if (PBCreate((ParmBlkPtr)&pb, 0)) {
- if (pb.ioResult == dirNFErr) {
- create_directory(fname);
- pb.ioNamePtr = c2pstr(strcpy(name, fname));
- pb.ioVRefNum = 0;
- pb.ioFVersNum = 0;
- if (PBCreate((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- }
- else if (pb.ioResult == dupFNErr) {
- /* most likely a clash because Unix FS is case-sensitive */
- fprintf(stderr, "%s: Warning: Duplicate filename, %s renamed to ", Program, fname);
- sprintf (name, "%s_%d", fname, fno++);
- fprintf(stderr, "%s\n", name);
- strcpy(fname, name);
- pb.ioNamePtr = c2pstr(name);
- if (PBCreate((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- }
- else pbsyserr(&pb);
- }
- pb.ioNamePtr = c2pstr(strcpy(name, fname));
- pb.ioVRefNum = 0;
- pb.ioFVersNum = 0;
- pb.ioFDirIndex = 0;
- if (PBGetFInfo((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- pb.ioNamePtr = c2pstr(strcpy(name, fname));
- pb.ioFlFndrInfo.fdType = TEXT;
- pb.ioFlFndrInfo.fdCreator = filecreator;
- if (PBSetFInfo((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
- }
-
- untar_link ()
- {
- unix2mac(tarh.name);
- unix2mac(tarh.linkname);
- fprintf(stderr, "%s: Warning: Link %s -> %s (ignored)\n", Program, tarh.name, tarh.linkname);
- }
-
- /* Convert Unix pathname to a mac pathname. Do not allow absolute
- names - "/foo/bar/baz" is treated as if it were "foo/bar/baz".
- */
- unix2mac (name)
- char *name;
- {
- char buf[102];
- char *cp = name, *bp = buf, *op;
- *bp++ = ':';
- op = bp;
- while (1) {
- if (cp[0] == '/') ++cp;
- else if (cp[0] == '.' && cp[1] == '/') cp += 2;
- else if (cp[0] == '.' && cp[1] == '.' && cp[2] == '/') {
- if (op == bp) *bp++ = ':', op = bp;
- else for (--op; op != bp && op[-1] != ':'; --op);
- cp += 3;
- }
- else {
- while (*cp && *cp != '/') if ((*op++ = *cp++) == ':') op[-1] = '/';
- if (!*cp++) break;
- *op++ = ':';
- }
- }
- *op = '\0';
- strcpy(name, buf);
- }
-
- ignore_file (file)
- char *file;
- {
- char **fp = files;
- int *ip = ffound;
- if (!fp) return 0;
- for (; *fp; ++fp, ++ip)
- if (match_file(*fp, file)) {
- ++ip[0];
- return 0;
- }
- return 1;
- }
-
- /* Name is the user-specified name, file is the actual tarred file */
- match_file (name, file)
- char *name, *file;
- {
- char *cp;
- if (!strdiff(name, file)) return 1;
- if ((cp = strrchr(file, ':')) && !strdiff(cp+1, name)) return 1;
- if (name[strlen(name)-1] == ':' && strdiff(name, file) >= 0) return 1;
- return 0;
- }
-
- /* return 0 if the same, 1 if s1 is a substring of s2, -1 otherwise */
- strdiff (s1, s2)
- char *s1, *s2;
- {
- while (*s1) {
- if (*s1 != *s2) {
- char c1 = *s1;
- if ('A' <= c1 && c1 <= 'Z') c1 |= 0x20;
- if ('a' > c1 || c1 > 'z' || c1 != (*s2 | 0x20)) return -1;
- }
- ++s1, ++s2;
- }
- return (*s2 ? 1 : 0);
- }
-
- untar_number (cp)
- char *cp;
- {
- int neg = 0, num = 0;
- while (*cp == ' ') cp++;
- if (*cp == '-') neg++, cp++;
- while ('0' <= *cp && *cp <= '7') num = (num<<3) + (*cp++ - '0');
- if (neg) num = -num;
- return num;
- }
-
- openpb(pb, name, perm)
- IOParam *pb;
- char *name;
- int perm;
- {
- pb->ioVRefNum = 0;
- pb->ioVersNum = 0;
- pb->ioPermssn = perm;
- pb->ioMisc = 0;
- pb->ioRefNum = 0;
- pb->ioNamePtr = c2pstr(name);
- if (PBOpen((ParmBlkPtr)pb, 0)) pbsyserr(pb);
- }
-
-
- readerr ()
- {
- if (feof(tarf)) fatal("Premature end of file");
- else fatal("Read error");
- }
-
- pbsyserr (pb)
- IOParam *pb;
- {
- int err = pb->ioResult;
- char *name = pb->ioNamePtr;
- p2cstr(name);
- if (err == fnfErr) fatal("%s - File not found", name);
- else if (err == nsvErr) fatal("%s - No such volume", name);
- else if (err == tmfoErr) fatal("%s - Too many files open", name);
- else if (err == permErr) fatal("%s - Permissions error", name);
- else if (err == dupFNErr) fatal("%s - Duplicate filename", name);
- else if (err == eofErr) fatal("%s - Premature end of file", name);
- else fatal("%s - Error #%d", name, err);
- }
-
- fatal(fmt, arg1, arg2, arg3, arg4, arg5, arg6)
- char *fmt, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
- {
- if (tarf && tarf != stdin) fclose(tarf);
- if (ffound) free(ffound);
- fflush(stdout);
- fprintf(stderr, "%s: ", Program);
- fprintf(stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
- fprintf(stderr, "\n");
- exit(2);
- }
-
-